package com.boodaba.todocarts.test.infstr;

import static org.junit.Assert.*;

import java.io.File;
import java.io.IOException;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.boodaba.todocarts.infstr.Db4oStoreContext;

public class Db4oStoreContextShould {
	private Db4oStoreContext SUT;
	
	private StoringSome mSomeObj1;
	private StoringSome mSomeObj2;
	private StoringSome mSomeObj3;
		
	private String mCode1;
	private String mCode2;
		
	private String mName1;
	private String mName2;
	private String mName3;
				
	private File mDbFile;
	
	@Before
	public void setUp() throws IOException {
		if (mDbFile == null) {
			mDbFile = File.createTempFile("dbfile", ".db4o");
			mDbFile.delete();
		}
		SUT = new Db4oStoreContext(mDbFile.getAbsolutePath());
		
		mSomeObj1 = new StoringSome();
		mSomeObj2 = new StoringSome();
		mSomeObj3 = new StoringSome();
				
		mCode1 = "some code 1";
		mCode2 = "2 codesome";
				
		mName1 = "name one";
		mName2 = "some title of";
		mName3 = "overwise name";
	}
	
	@After
	public void clearDown() throws IOException {
		SUT.close();
		SUT = null;
		mDbFile.delete();
	}
	
	@Test
	public void simplySaveAndRetreiveBySpecification() {
		mSomeObj1.Code = mCode1;
		mSomeObj2.Code = mCode2;
		mSomeObj3.Code = mCode1;
		
		SUT.save(mSomeObj1);
		SUT.save(mSomeObj2);
		SUT.save(mSomeObj3);
		
		SomeIdSpecification spec1 = new SomeIdSpecification(mCode1);
		SomeIdSpecification spec2 = new SomeIdSpecification(mCode2);
		SomeIdSpecification spec3 = new SomeIdSpecification("");
		
		//online
		assertTrue(SUT.findBySpecification(spec1).size() == 2);
		assertTrue(SUT.findBySpecification(spec2).size() == 1);
		assertTrue(SUT.findBySpecification(spec3).size() == 0);
		
		StoringSome ss1 = SUT.getBySpecification(spec1);
		StoringSome ss2 = SUT.getBySpecification(spec2);
		StoringSome ss3 = SUT.getBySpecification(spec3);
		
		assertTrue(ss1.Code.equals(mCode1));
		assertTrue(ss2.Code.equals(mCode2));
		assertTrue(ss3 == null);
		
		//offline
		reopenDb();
		assertTrue(SUT.findBySpecification(spec1).size() == 2);
		assertTrue(SUT.findBySpecification(spec2).size() == 1);
		assertTrue(SUT.findBySpecification(spec3).size() == 0);
		
		ss1 = SUT.getBySpecification(spec1);
		ss2 = SUT.getBySpecification(spec2);
		ss3 = SUT.getBySpecification(spec3);
		
		assertTrue(ss1.Code.equals(mCode1));
		assertTrue(ss2.Code.equals(mCode2));
		assertTrue(ss3 == null);
	}
	
	@Test
	public void simplyDelete() {
		SUT.save(mSomeObj1);
		SUT.save(mSomeObj2);
		SUT.save(mSomeObj3);
		
		SUT.delete(mSomeObj1);
		assertTrue(SUT.allOf(StoringSome.class).size() == 2);
		SUT.delete(mSomeObj1);
		assertTrue(SUT.allOf(StoringSome.class).size() == 2);
		SUT.delete(mSomeObj3);
		assertTrue(SUT.allOf(StoringSome.class).size() == 1);		
	}
	
	@Test
	public void persistSaved() {
		SUT.save(mSomeObj1);
		reopenDb();
		assertTrue(SUT.allOf(StoringSome.class).size() == 1);
		
		SUT.save(mSomeObj1);
		//goes through offline
		reopenDb();
		assertTrue(SUT.allOf(StoringSome.class).size() == 2);
		
		SUT.save(mSomeObj2);
		assertTrue(SUT.allOf(StoringSome.class).size() == 3);
	}
	
	@Test
	public void bindCorrectlyIfSaving() {
		mSomeObj1.Code = mCode1;
		mSomeObj2.Code = mCode1;
		mSomeObj3.Code = mCode1;
		mSomeObj1.Name = mName1;
		mSomeObj2.Name = mName2;
		mSomeObj3.Name = mName3;
		
		SomeIdSpecification spec = new SomeIdSpecification(mCode1);
		
		//online
		SUT.save(mSomeObj1);
		SUT.bindBySpecification(mSomeObj2, spec);
		SUT.save(mSomeObj2);
		
		assertTrue(SUT.allOf(StoringSome.class).size() == 1);
		assertTrue(SUT.getBySpecification(spec).Name.equals(mName2));
		
		//offline
		reopenDb();
		SUT.bindBySpecification(mSomeObj3, spec);
		SUT.save(mSomeObj3);
		reopenDb();
		assertTrue(SUT.allOf(StoringSome.class).size() == 1);
		assertTrue(SUT.getBySpecification(spec).Name.equals(mName3));
	}
	
	@Test
	public void bindCorrectlyIfDeleting() {
		mSomeObj1.Code = mCode1;
		mSomeObj2.Code = mCode2;
		mSomeObj3.Code = mCode1;
						
		SomeIdSpecification spec = new SomeIdSpecification(mCode1);
		
		//online
		SUT.save(mSomeObj1);
		SUT.save(mSomeObj2);
		
		SUT.bindBySpecification(mSomeObj3, spec);
		SUT.delete(mSomeObj3);
		
		assertTrue(SUT.allOf(StoringSome.class).size() == 1);
				
		//offline
		reopenDb();
		spec = new SomeIdSpecification(mCode2);
		mSomeObj3.Code = mCode2;
		SUT.bindBySpecification(mSomeObj3, spec);
		SUT.delete(mSomeObj3);
		assertTrue(SUT.allOf(StoringSome.class).size() == 0);
		
		reopenDb();
		assertTrue(SUT.allOf(StoringSome.class).size() == 0);
	}
	
	@Test
	public void keepUpdatedItemsContained() {
		mSomeObj1.Code = mCode1;
		mSomeObj2.Code = mCode2;
		mSomeObj1.add(mSomeObj2);
		
		SUT.save(mSomeObj1);
				
		reopenDb();
		
		SomeIdSpecification spec = new SomeIdSpecification(mCode1);
		
		StoringSome ss1 = SUT.getBySpecification(spec);
		StoringSome ss2 = ss1.getAll().get(0);
		assertTrue(ss2.Code.equals(mCode2));
		ss2.Name = mName3;
		SUT.save(ss1);
		ss1 = SUT.getBySpecification(spec);
		assertTrue(ss1.getAll().get(0).Name.equals(mName3));
		reopenDb();
		ss1 = SUT.getBySpecification(spec);
		assertTrue(ss1.getAll().get(0).Name.equals(mName3));
	}
	
	@Test
	public void nothingJustSeeBehavior() {
		mSomeObj1.Code = mCode1;
		mSomeObj2.Code = mCode2;
		
		SUT.save(mSomeObj1);
		SUT.save(mSomeObj2);
		
		reopenDb();
		SomeIdSpecification spec1 = new SomeIdSpecification(mCode1);
		SomeIdSpecification spec2 = new SomeIdSpecification(mCode2);
		
		mSomeObj2 = SUT.getBySpecification(spec2);
		
		// comment this to get test failed
		reopenDb();
		
		mSomeObj2.Code = mCode1;
		
		assertTrue(SUT.findBySpecification(spec1).size() == 1);
	}
	
	private void reopenDb() {
		if (SUT != null) {
			SUT.close();
		}
		SUT = new Db4oStoreContext(mDbFile.getAbsolutePath());
	}
}
